﻿// Inner Fire 游戏引擎库
// 描述符管理类
//
// Copyright (c) 2024 by 尔西大帝. All rights reserved.
//
// 这个类提供上传到默认缓冲区（或其它）的快捷操作。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-12-05

#pragma once

#include <dx/core/dx_core.h>
#include <index_allocator.h>

namespace ifire::dx {
// 用于阴影的DSV
constexpr int SHADOW_DSV_INDEX = 1;
// 用于UI的DSV
constexpr int UI_DSV_INDEX = 2;

struct DxDescriptorDesc {
  int TextureCount;
  int WavesCount;
  int SobelCount;
};

class DxDescriptor {
public:
  DxDescriptor() = default;
  DxDescriptor(const DxDescriptor& rhs) = delete;
  DxDescriptor& operator=(const DxDescriptor& rhs) = delete;
  ~DxDescriptor() = default;

  void Init(ID3D12Device* device);
  // 为项目建立合适的描述符堆
  void BuildSrv(const DxDescriptorDesc& desc);
  // 指定空白法线贴图
  void AssignEmptyNormalMap(ID3D12Resource* res);
  // 指定天空盒贴图
  void AssignSkyBox(ID3D12Resource* res);

  void BuildRtv();
  void BuildDsv();
  
  // 为一个贴图创建一个描述符，返回在描述符堆中的索引
  // 返回的索引是从0开始的。因为在内部有一个位置标志Texture的起启位置。
  // 所以来源于外部的Index只需要关注他们的项目。
  UINT CreateTexture(TextureType type, ID3D12Resource* res);

  // 返回指定位置的CPU描述符Handle
  CD3DX12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(int offset);
  // 返回指定位置的GPU描述符Handle
  CD3DX12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(int offset);
  // 返回DSV指定位置的CPU描述符
  CD3DX12_CPU_DESCRIPTOR_HANDLE GetDsv(int offset);
  // 返回RTV指定位置的CPU描述符
  CD3DX12_CPU_DESCRIPTOR_HANDLE GetRtv(int offset) const;

  //// 获得贴图的开始位置
  //CD3DX12_CPU_DESCRIPTOR_HANDLE GetTextureStart();
  // 获得单个贴图的位置
  CD3DX12_GPU_DESCRIPTOR_HANDLE GetTextureGpu(int texture_index);
public:
  // 各种堆的大小，虽然说它是类变量，但应该像常量一样对待
  UINT RTV_SIZE;
  UINT DSV_SIZE;
  UINT CBV_SRV_UAV_SIZE;

  ComPtr<ID3D12DescriptorHeap> rtv_heap_; // 渲染目标视图资源
  ComPtr<ID3D12DescriptorHeap> dsv_heap_; // 深度/模板视图资源
  ComPtr<ID3D12DescriptorHeap> cbv_heap_; // 常量缓冲区视图
  ComPtr<ID3D12DescriptorHeap> srv_heap_; // 着色器资源视图

  UINT mRtvSwapChainIndex;
  UINT mRtvScreenNormalMapIndex;
  UINT mRtvAmbientMapIndex;
  UINT mRtvOffscreenIndex;

  UINT mNullCubeIndex = 0;
  UINT mNullTextureIndex = 0;
  UINT mEmptyNormalIndex = 0;
  UINT mSkyBoxIndex = 0;
  UINT mShadowMapIndex = 0;
  UINT mSsaoIndex = 0;
  UINT mSsaoAmbientIndex = 0;
  UINT mWavesIndex = 0;
  UINT mSobelIndex = 0;
  UINT mOffscreenIndex = 0;
  UINT mDisplacementIndex = 0;
  UINT mUIDepthMapIndex = 0;

  // Texture索引在描述符堆中的位置
  UINT mTextureStartIndex = 0;
  // 当前的Texture的索引
  UINT mTextureCurrentIndex = 0;
  

  // 用于引用空白的天空盒
  CD3DX12_GPU_DESCRIPTOR_HANDLE mNullCube;
  // 用于引用空白的纹理
  CD3DX12_GPU_DESCRIPTOR_HANDLE mNullTexture;
  // 用于引用空白的法线
  CD3DX12_GPU_DESCRIPTOR_HANDLE mEmptyNormal;
  // 用于引用天空盒纹理
  CD3DX12_GPU_DESCRIPTOR_HANDLE mSkyBox;

  D3D12_SHADER_RESOURCE_VIEW_DESC mNullDesc;
  D3D12_SHADER_RESOURCE_VIEW_DESC mCubeDesc;
  D3D12_SHADER_RESOURCE_VIEW_DESC mImageDesc;
  D3D12_SHADER_RESOURCE_VIEW_DESC mTexArrayDesc;

private:
  void BuildDesc();
  void BuildNullSrv();

private:
  // 设备的句柄
  ID3D12Device* device_;
  // 用于设置索引
  ikit::index_allocator index_;
  // 用于设置RTV索引
  ikit::index_allocator rtv_index_;
};
} // namespace ifire